import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.LayoutManager;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;


public class UserInterface {
	private static boolean serverRunning = false;
	private static ServerTimer serverTimer;
	private static Frame frame;
	private static JPanel topPanel;
	private static JPanel midPanel;
	private static JPanel rightPanel;
	private static JButton buttonStart;
	private static JTextArea textArea;
	private static JScrollPane scrollPane;
	private static JTextArea textAreaClients;
	private static JScrollPane scrollPaneClients;
	private static JList listbox;
	private static JTextField tfMessage;
	private static JTextField tfPlayers;
	private static JTextField tfPort;
	private static JComboBox cbArena;
	private static JComboBox cbPlayers;
	private static ArrayList<Client> activeClients;
	private static DefaultListModel clientsData = new DefaultListModel();
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		frame = new Frame(Settings.ApplicationTitle);
		frame.setResizable(false);
		frame.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);
			}
		});
		
		//Create the form
		JPanel panel=new JPanel();
		panel.setPreferredSize(new Dimension(400, 600));
		
		topPanel = new JPanel();
		topPanel.setPreferredSize(new Dimension(500, 100));
		panel.add(topPanel);
		
		JPanel topLeftPanel = new JPanel((LayoutManager) new FlowLayout(FlowLayout.LEFT));
		topLeftPanel.setPreferredSize(new Dimension(135, 100));
		topPanel.add(topLeftPanel);
		
		JLabel labelArena = new JLabel("Select arena:");
		labelArena.setPreferredSize(new Dimension(225, 20));
		topLeftPanel.add(labelArena);
		
		String[] arenas = { "Default" };
		cbArena = new JComboBox(arenas);
		cbArena.setSelectedIndex(0);
		topLeftPanel.add(cbArena);
		
		JPanel topMidPanel = new JPanel((LayoutManager) new FlowLayout(FlowLayout.LEFT));
		topMidPanel.setPreferredSize(new Dimension(175, 100));
		topPanel.add(topMidPanel);
		
		JLabel labelAmountOfPlayers = new JLabel("Max amount of players:");
		labelAmountOfPlayers.setPreferredSize(new Dimension(225, 20));
		topMidPanel.add(labelAmountOfPlayers);
		
		String[] playerAmounts = { "4", "6", "8", "10", "12"};
		cbPlayers = new JComboBox(playerAmounts);
		cbPlayers.setSelectedIndex(0);
		topMidPanel.add(cbPlayers);
		
		JPanel topRightPanel = new JPanel();
		topRightPanel.setPreferredSize(new Dimension(140, 100));
		topPanel.add(topRightPanel);

		JLabel labelPort = new JLabel("Port:");
		labelPort.setPreferredSize(new Dimension(40, 20));
		topRightPanel.add(labelPort);
		
		tfPort = new JTextField("6789");
		tfPort.setPreferredSize(new Dimension(60, 20));
		topRightPanel.add(tfPort);
		
		buttonStart = new JButton("Start server");
		buttonStart.setBounds(0, 0, 80, 40);
		buttonStart.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					try {
						startServer();
					} catch (Exception e1) {}
				}
			}
		);
		topRightPanel.add(buttonStart); //set layout null?
		
		midPanel=new JPanel();
		midPanel.setPreferredSize(new Dimension(300, 400));
		panel.add(midPanel);
		
		rightPanel=new JPanel();
		rightPanel.setPreferredSize(new Dimension(180, 400));
		panel.add(rightPanel);
		
		textArea= new JTextArea("",24,24);
		redirectSystemStreams();
		textArea.setLineWrap(true);
		textArea.setEditable(false);
		
		scrollPane = new JScrollPane(textArea);
		scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		
		listbox = new JList(clientsData);
		listbox.setPreferredSize(new Dimension(180, 200));
		listbox.setBorder(BorderFactory.createLineBorder(Color.black));
		listbox.setFixedCellWidth(10);
		listbox.addMouseListener(new MouseAdapter() {
		    public void mouseClicked(MouseEvent evt) {
		        JList list = (JList)evt.getSource();
		        if (evt.getClickCount() == 1) { //single click, use 2 for double click
		            int index = list.locationToIndex(evt.getPoint()); //-1 if nothing selected
		            if(index >= 0){ //valid selection
		            	Client selection = activeClients.get(index);
		            	textAreaClients.setText(selection.getName()
		            			+ ":\n\nClient ID: " + selection.getClientId()
		            			+ "\nIP-Address: " + selection.getClientAddress()
		            			+ "\n\nBounds: " + selection.getPlayerData());
		            }
		            else textAreaClients.setText("");
		        }
		    }
		});
		rightPanel.add(listbox);
		textAreaClients= new JTextArea("",11,14); //Textarea for clients
		textAreaClients.setLineWrap(true);
		textAreaClients.setEditable(false);
		
		scrollPaneClients = new JScrollPane(textAreaClients);
		scrollPaneClients.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

		frame.add(panel);
		//panel.add(scrollPane);
		midPanel.add(scrollPane);
		rightPanel.add(scrollPaneClients);

		JPanel bottomPanel = new JPanel();
		bottomPanel.setPreferredSize(new Dimension(480, 100));
		panel.add(bottomPanel);
		
		tfMessage = new JTextField();
		tfMessage.setPreferredSize(new Dimension(392, 20));
		bottomPanel.add(tfMessage);
		
		JButton btnSend = new JButton("Send");
		btnSend.setBounds(0, 0, 80, 40);
		btnSend.addActionListener(
			new ActionListener(){
				public void actionPerformed(ActionEvent e){
					//action
				}
			}
		);
		bottomPanel.add(btnSend); //set layout null?

		frame.setSize(500, 600);
		frame.setVisible(true);
	}
	
	private static void startServer(){
		Settings.port = Integer.parseInt(tfPort.getText());
		Settings.maximumAmountOfPlayers = Integer.parseInt(cbPlayers.getSelectedItem().toString());
		ConnectionHandler.getInstance().startAcceptingConnections();
		Settings.ipAddress = getServerIP();
		System.out.println("Server IP-address: " + Settings.ipAddress + "\nServer port: " + Settings.port);
		try {
			InetAddress thisIp =InetAddress.getLocalHost();
			System.out.println("Local IP: "+thisIp.getHostAddress());
		}catch(Exception e){}
		System.out.println("\n");
		//System.out.println("Online registration: " + getRegisterResult());
		serverRunning = true;
		serverTimer = new ServerTimer();
		serverTimer.startTimer();
		buttonStart.setEnabled(false);
		updateTimePassed(0);
		
		// Start the webconnection for updating this server in the battlelag server list
		WebConnection.getInstance().start();
	}

	private static void redirectSystemStreams() {
		OutputStream out = new OutputStream() {
			@Override
			public void write(int b) throws IOException {
				updateTextArea(String.valueOf((char) b));
			}

			@Override
			public void write(byte[] b, int off, int len) throws IOException {
				updateTextArea(new String(b, off, len));
			}

			@Override
			public void write(byte[] b) throws IOException {
				write(b, 0, b.length);
			}
		};

		System.setOut(new PrintStream(out, true));
		System.setErr(new PrintStream(out, true));
	}
	private static void updateTextArea(final String text) 
	{
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				textArea.append(text);
			}
		});
	}
	private static String getTime(){
		Date date = new Date();
		return date.toString() + ": ";
	}
	
	/**
	 * Updates the textarea of clients, which shows all currently connected clients.
	 * @param clients
	 */
	public static void updateClients(ArrayList<Client> clients){
		activeClients = clients;
		clientsData.clear();
		for(int i = 0; i < clients.size(); i++)
			clientsData.addElement(clients.get(i).toString());
	}
	
	public static void updateClients(){
		updateClients(ConnectionHandler.getInstance().getActiveClients());
	}
	
	/**
	 * Update the time that has passed since the server was started.
	 * @param timePassedInSeconds
	 */
	public static void updateTimePassed(int timePassedInSeconds){
		int seconds = timePassedInSeconds;
		int minutes = seconds / 60;
		seconds -= (minutes*60);
		int hours = minutes/60;
		minutes -= (hours*60);
		
		String minutesAsString = beautifyDigit(Integer.toString(minutes));
		String secondsAsString = beautifyDigit(Integer.toString(seconds));
		
		
		String timeString = minutesAsString + ":" + secondsAsString;
		if(hours > 0)
			timeString = hours + ":" + timeString;
		updateTitle(timeString);
	}
	
	private static String beautifyDigit(String digit){
		String result = digit;
		if(result.length() == 1)
			result = "0" + result;
		return result;
	}
	
	private static void updateTitle(String time){
		String title = Settings.ApplicationTitle;
		if(serverRunning)
			title += " - RUNNING:   " + time;
		frame.setTitle(title);
	}
	
	/**
	 * Connects to a website to find the ip of the server.
	 * @return
	 */
	private static String getServerIP(){
		return getHttpRequestResult("http://api.externalip.net/ip/");
	}
	/**
	 * Connects to website and registers this server. Returns if the process has succeeded.
	 * @return
	 */
	private static String getRegisterResult(){
		return getHttpRequestResult(Settings.registrationUrl+"?serverport=" + Settings.port
				+ "&maxplayers=" + Settings.maximumAmountOfPlayers);
	}
	/**
	 * Connects to a website and returns the result.
	 * @return
	 */
	private static String getHttpRequestResult(String url){
		try{
			URL requestUrl = new URL(url);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					requestUrl.openStream()));

			String result = in.readLine(); //you get the IP as a String
			in.close();
			return result;
			}catch(Exception e){return "Not found.";}
	}
}
